package org.rescue.analysis.taxonomy;

/*
 * INPUT: concept (new name: taxonomy): concept_id, label, parent_id (the taxonomy graph)
 * 		  taxonomy (new name: closure) : concept_id, ancestor_id, ancestor_level (its transitive closure)
 * 		  annotation: doc_id, taxonomy_id, concept_id, confidence  
 * 
 * Algo:
 * 1. Get annotationset_id, taxonomy_id (from annotationset table, get the taxonomy id)
 * 2. select concept_id, count()
 *    from annotation table
 *    where taxonomy_id = "x"
 *    group by concept_id 
 * 4. Load concepts to Hashtable
 * 5. ConcepttoRoot reader.   
 *
 * OUTPUT: finally, push result concepts to a resultconc table, join with
 *         concept table to ge the labels. 
 */


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.swing.tree.DefaultMutableTreeNode;

import org.rescue.analysis.summarize.Concept;
import org.rescue.search.Dataset;
import org.rescue.search.Document;
import org.rescue.data.extraction.Location;

public class SummarizeSubTaxonomyDB {
    Map<Integer, DefaultMutableTreeNode> conceptToNodeMap = new HashMap<Integer, DefaultMutableTreeNode>();
    Map<Integer, Concept> conceptToNodeDataMap = new HashMap<Integer, Concept>();
    DefaultMutableTreeNode rootConceptNode = null;
    int rootConcept;
    int totalCard;

    public DefaultMutableTreeNode readTaxonomy(String annot_table, String tax_table,
    		int tax_id, String closure_table) {
    	String annot = annot_table;
    	String tax = tax_table;
    	String closure = closure_table;
   	
    	String loginUser = "hurricane-dev";
	    String loginPasswd = "hurricane-dev";
	    //String loginUrl = "jdbc:mysql://rescue-ibm.calit2.uci.edu:3306/hurricane-dev";	
	    String loginUrl = "jdbc:mysql://128.195.185.173:3306/hurricane-dev2";
	    
        ArrayList<Integer> conceptToRoot = new ArrayList<Integer>();
        int concept = 0; int prev_concept = 0;
        
		try {
			Class.forName("com.mysql.jdbc.Driver").newInstance();
			Connection conn = DriverManager.getConnection(loginUrl,loginUser,loginPasswd);
	      
	        PreparedStatement stmt = null;
	        ResultSet rs = null;
	        
	        rootConcept = 1; // since root is assigned 1
	        rootConceptNode = getConceptNode(rootConcept);
	        
	        /* 1. Read concepts and load to HashMap */
	        readConcepts(stmt, conn, annot, tax, tax_id);
		        
	        /* 2. load sub-taxonomy*/
			stmt = conn.prepareStatement(
					"SELECT DISTINCT t.concept_id, t.ancestor_id, t.ancestor_distance "
					+ "FROM " + closure + " t, " + annot + " a "
					+ "WHERE a.taxonomy_id = " + tax_id + " AND a.concept_id = t.concept_id "
					+ "ORDER BY t.concept_id, t.ancestor_distance;"
			);

	        rs = stmt.executeQuery();
	        // ConeptToRoot reading
	        while (rs.next()) {
	        	concept  = rs.getInt("concept_id");
	        	if (concept != prev_concept) {
	        		if (prev_concept != 0) {
	        			insertCToR(conceptToRoot);
	        		}
	        		prev_concept = concept;	        		
        			conceptToRoot.clear(); 
        			conceptToRoot.add(concept);
	        		conceptToRoot.add(rs.getInt("ancestor_id"));
	        	}
	        	else {
	        		conceptToRoot.add(rs.getInt("ancestor_id"));	        		
	        	}
	        }
        	// insert last concept's conceptToRoot
        	if (!conceptToRoot.isEmpty()) {
        		insertCToR(conceptToRoot);
        	}	        	
	        
		    rs.close();
	        stmt.close();
	        conn.close();
	    } catch (SQLException ex) {
	        while (ex!=null){
	            System.err.println("SQLException: " + ex.getMessage());
	            System.err.println("SQLState: " + ex.getSQLState());
	            System.err.println("VendorError: " + ex.getErrorCode());
	            ex = ex.getNextException();
	        }
	    }
		catch (Exception ex) {
			System.err.println("Exception: " + ex.getMessage());
		}
		((Concept)rootConceptNode.getUserObject()).card = totalCard;
		return rootConceptNode;
    }    
    
    public void readConcepts(PreparedStatement stmt, Connection conn, String annot_table,
    		String tax_table, int tax_id) {
    	totalCard = 0;
    	try{
    		stmt = conn.prepareStatement("SELECT concept_id, count(*) cnt FROM " + annot_table
    				+ " WHERE taxonomy_id = ? GROUP BY concept_id;");
    		    		
    		stmt.setInt (1, tax_id);
    		ResultSet rs = stmt.executeQuery();   

    		while (rs.next()) {    		
    			DefaultMutableTreeNode conceptNode;
    			int concept = rs.getInt("concept_id");
    			int cnt = rs.getInt("cnt");
    			totalCard += cnt;
    			// System.out.println(concept + "  " + totalCard);

    			if (conceptToNodeMap.containsKey(concept)) {
    				if (concept == rootConcept) {
    					conceptNode = conceptToNodeMap.get(concept);
    					((Concept)conceptNode.getUserObject()).dCard = cnt;
    				}
    			}
    			else {
    				Concept conceptNodeData = new Concept();
    				conceptNodeData.setId (concept);
    				conceptNodeData.setDCard(cnt);
    				conceptToNodeDataMap.put(concept,conceptNodeData);
    			}
    		}
    	}catch (SQLException ex) {
    		while (ex!=null){
    			System.err.println("SQLException: " + ex.getMessage());
    			System.err.println("SQLState: " + ex.getSQLState());
    			System.err.println("VendorError: " + ex.getErrorCode());
    			ex = ex.getNextException();
    		}
    	}
    }
    
	public void insertCToR(ArrayList<Integer> conceptToRoot) {
		int parentConcept, childConcept;
		Collections.reverse(conceptToRoot);
		Iterator<Integer> it = conceptToRoot.iterator();
		DefaultMutableTreeNode childConceptNode, parentConceptNode;
		
		parentConcept = it.next();
		parentConceptNode = getConceptNode(parentConcept);
		// add parentConcept to rootConcept
		//if (parentConceptNode.getParent() != rootConceptNode) {
		if (parentConceptNode != rootConceptNode) {
			System.err.println("Root concept not in concept-to-root path !");
		}		
		while (it.hasNext()) {
			childConcept = it.next();
			childConceptNode = getConceptNode(childConcept);
			
			// add to taxonomy tree
			if (childConceptNode.getParent() != parentConceptNode) {
				parentConceptNode.add(childConceptNode);
			}
			parentConceptNode = childConceptNode;
		}
	}
    
	public DefaultMutableTreeNode getConceptNode(int concept) {
		DefaultMutableTreeNode conceptNode; 
		if (conceptToNodeMap.containsKey(concept)) {
			// have already see the concept
			conceptNode = (DefaultMutableTreeNode) conceptToNodeMap.get(concept);
		}
		else { // insert to concept map
			conceptNode = new DefaultMutableTreeNode();
			if (conceptToNodeDataMap.containsKey(concept)) {
				conceptNode.setUserObject((ConceptNodeData)conceptToNodeDataMap.get(concept));
			} 
			else { // create empty conceptNodeData
				Concept conceptNodeData = new Concept();
				conceptNodeData.setId(concept);
			//	conceptNodeData.setLabel(concept);
				conceptNode.setUserObject(conceptNodeData);
			}
			conceptToNodeMap.put(concept, conceptNode);
		}
		return conceptNode;
	}

	public void printTaxonomy(DefaultMutableTreeNode t) {
		Enumeration e = t.breadthFirstEnumeration();			
		
		while (e.hasMoreElements()) {
			DefaultMutableTreeNode conceptNode = (DefaultMutableTreeNode)e.nextElement();
			ConceptNodeData conceptNodeData = (ConceptNodeData)conceptNode.getUserObject();
			System.out.println(conceptNodeData.getId() + " " + 
					" dCardinality: " + conceptNodeData.getDCard());			
		}

	}

	public String getTaxonomyAsXmlTree(DefaultMutableTreeNode t, String name) {
		
		String xml = "";
		
		xml += "<taxonomy name=\"" + name + "\">\n";  
		xml += getTaxonomyAsXmlTreeHelper(t);
		xml += "</taxonomy>";
		
		return xml;
	}
	
	public String getTaxonomyAsXmlTreeHelper(DefaultMutableTreeNode t) {

		String xml = "";
		ConceptNodeData conceptNodeData = (ConceptNodeData)t.getUserObject();	
		
		
		if (t.isLeaf()) {		
			xml += "<concept name=\"" + conceptNodeData.getLabel() + "\" id=\"" + conceptNodeData.getId() + "\"></concept>\n";
		}
		else {
			xml += "<concept name=\"" + conceptNodeData.getLabel() + "\" id=\"" + conceptNodeData.getId() + "\">\n";
			Enumeration e = t.children();
			while (e.hasMoreElements()){
				xml += getTaxonomyAsXmlTreeHelper((DefaultMutableTreeNode)e.nextElement());
			}
			xml += "</concept>\n";
		}
		

		return xml;
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {

		DefaultMutableTreeNode testTaxonomy;
		Dataset dataset = new Dataset();
		
		Document doc;
		doc = new Document();
		doc.setId(1);
		doc.addLocation("Irvine","city");
		doc.addLocation("VA","state");
		dataset.addDocument(doc);
		
		doc = new Document();
		doc.setId(2);
		doc.addLocation("Alexandria","city");
		doc.addLocation("El Segundo","city");
		dataset.addDocument(doc);
				
		SummarizeSubTaxonomyDB taxonomyReader = new SummarizeSubTaxonomyDB();
//		ConceptToRootReader ctorReader = new LocationCToRReader();
		// testTaxonomy = taxonomyReader.readTaxonomy(ctorReader, dataset);
		// taxonomyReader.printTaxonomy(testTaxonomy);
//		System.out.print(taxonomyReader.getTaxonomyAsXmlTree(testTaxonomy,"Taxonomy #: " + taxonomyId.toString()));
	}

}
